home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / mint / lib / mntlib44.zoo / mntlib / strtoul.c < prev    next >
C/C++ Source or Header  |  1992-09-05  |  3KB  |  109 lines

  1. /* original from norbert schelenkar's stdio */
  2. /* eff hacks    ++jrb */
  3. /* conversion to ansi spec -- mj */
  4. /* 
  5.  * Base can be anything between 2 and 36 or 0.
  6.  * If not NULL then resulting *endptr points to the first
  7.  * non-accepted character.
  8.  */
  9.  
  10. #include <ctype.h>
  11. #include <errno.h>
  12. #include <limits.h>
  13. #include <stddef.h>
  14. #include <stdlib.h>
  15.  
  16. /* macro to avoid most frequent long muls on a lowly 68k */
  17. #define _BASEMUL(B, SH, X) \
  18.     ((0 != SH) ? \
  19.        ((10 == (B)) ? ((((X) << (SH)) + (X)) << 1) : ((X) << (SH))) : \
  20.        ((X) * (B))) 
  21.  
  22. unsigned long int strtoul(nptr, endptr, base)
  23. register const char *nptr;
  24. char **endptr;
  25. int base;
  26. {
  27.   register short c;
  28.   unsigned long result = 0L;
  29.   unsigned long limit;
  30.   short negative = 0;
  31.   short overflow = -2; /* if this stays negative then
  32.               no conversion was performed */
  33.   short digit;
  34.   int shift;
  35.   unsigned long top = ULONG_MAX;
  36.  
  37.   if (endptr != NULL)
  38.       *endptr = (char *)nptr;
  39.  
  40.   do {             /* skip leading white space */
  41.       c = *nptr++;
  42.   } while (isspace(c));
  43.  
  44.   if (c == '+')     /* handle signs */
  45.       c = *nptr++;
  46.   else if (c == '-') {
  47.       negative = 1;
  48.       c = *nptr++;
  49.   }
  50.  
  51.   if ((base == 0) || (base == 16)) {     /* discard 0x/0X prefix if hex */
  52.       if (c == '0') {
  53.       if (*nptr == 'x' || *nptr == 'X') {
  54.               if (endptr != NULL)
  55.                   *endptr = (char *) nptr;
  56.           nptr += 1;
  57.           c = *nptr++;
  58.           base = 16;
  59.       }
  60.       }
  61.   }
  62.   if (base == 0)             /* determine base if unknown */
  63.       base = (c == '0') ? 8 : 10;    /* don't skip leading 0 if present */
  64.   else if (base < 2 || base > 36)
  65.       return result;
  66.  
  67.   limit = top/(unsigned long)base;     /* ensure no overflow */
  68.   shift = 0;
  69.   switch (base) {
  70.       case 32: shift++;
  71.       case 16: shift++;
  72.       case 8: shift++;
  73.       case 4: case 10: shift++;
  74.       case 2: shift++;
  75.       default:;
  76.   }
  77.   
  78.   do {            /* convert the number */
  79.       if (isdigit(c))
  80.       digit = c - '0';
  81.       else if (isalpha(c))
  82.       digit = c - (isupper(c) ? 'A' : 'a') + 10;
  83.       else
  84.       break;
  85.       if (digit >= base)
  86.       break;
  87.       if (0 == (overflow &= 1)) {    /* valid digit
  88.                        - some conversion performed */
  89.       if ((result > limit) ||
  90.           ((unsigned long) digit >
  91.            (result = _BASEMUL(base, shift, result), top - result))) {
  92.           result = top;
  93.           errno = ERANGE;
  94.           overflow = 1;
  95.           negative = 0;
  96.       }
  97.       else 
  98.           result += digit;
  99.       }
  100.   } while ((c = *nptr++) != 0);
  101.  
  102.   if (negative)                /* ANSI says we should do this! */
  103.     result = 0L - result;
  104.  
  105.   if ((endptr != NULL) && (overflow >= 0))     /* move *endptr if some */
  106.       *endptr = (char *) nptr - 1;              /* digits were accepted */
  107.   return result;
  108. }
  109.